/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package htpdf;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.util.PDFMergerUtility;

/**
 *
 * @author Puneet
 */
public class Main {

    public static final List<String> files = Collections.synchronizedList(new ArrayList<String>());
    public static final List<InputStream> pdfs = Collections.synchronizedList(new ArrayList<InputStream>());
    public static String basefile = "C:\\";
    private static final int pagecount = 30;
    public static byte[][] buf = new byte[pagecount][];
    private static List<Future<ByteArrayInputStream>> futures = new ArrayList<Future<ByteArrayInputStream>>();
    private static final Date date = new Date();
    private static StringBuilder urlStr = null;
    private static StringBuilder mergePaper = null;
    

    private static enum English_City {

        MUMBAI, DELHI, CHANDIGARH, KOLKATA,
    }

    private static enum Hindi_City {

        DELHI, RANCHI, PATNA, LUCKNOW,
    }

    private static enum Language {

        ENGLISH, HINDI,
    }

    private static Language language;

    public static void buildURL(String[] args){

        Format format = new SimpleDateFormat("yyyy/MM/dd");
        String dateStr = format.format(date);
        String pageStr = new SimpleDateFormat("dd_MM_yyyy_").format(date);
        if(Language.ENGLISH.name().toUpperCase().startsWith(args[0].toUpperCase())){
            urlStr = new StringBuilder("http://epaper.hindustantimes.com/PUBLICATIONS//HT/");
            mergePaper = new StringBuilder(basefile + "Hindustan_Times");
            if(English_City.DELHI.name().toUpperCase().startsWith(args[1].toUpperCase())){
                urlStr.append("HD/");
                mergePaper.append("_").append(English_City.DELHI.name());
            }else if(English_City.MUMBAI.name().toUpperCase().startsWith(args[1].toUpperCase())){
                urlStr.append("HM/");
                 mergePaper.append("_").append(English_City.MUMBAI.name());
            }else if(English_City.KOLKATA.name().toUpperCase().startsWith(args[1].toUpperCase())){
                urlStr.append("HK/");
                 mergePaper.append("_").append(English_City.KOLKATA.name());
            }else if(English_City.CHANDIGARH.name().toUpperCase().startsWith(args[1].toUpperCase())){
                urlStr.append("HC/");
                 mergePaper.append("_").append(English_City.CHANDIGARH.name());
            }else{
                System.out.println("INVALID CITY");
                System.exit(0);
            }
            

        }else if(Language.HINDI.name().toUpperCase().startsWith(args[0].toUpperCase())){
            urlStr = new StringBuilder("http://epaper.hindustandainik.com/PUBLICATIONS//HT/");
            mergePaper = new StringBuilder(basefile + "Hindustan_Dainik");
            if(Hindi_City.DELHI.name().toUpperCase().startsWith(args[1].toUpperCase())){
                urlStr.append("HT/");
                mergePaper.append("_").append(Hindi_City.DELHI.name());
            }else if(Hindi_City.RANCHI.name().toUpperCase().startsWith(args[1].toUpperCase())){
                urlStr.append("HR/");
                mergePaper.append("_").append(Hindi_City.RANCHI.name());
            }else if(Hindi_City.PATNA.name().toUpperCase().startsWith(args[1].toUpperCase())){
                urlStr.append("HP/");
                mergePaper.append("_").append(Hindi_City.PATNA.name());
            }else if(Hindi_City.LUCKNOW.name().toUpperCase().startsWith(args[1].toUpperCase())){
                urlStr.append("HL/");
                mergePaper.append("_").append(Hindi_City.LUCKNOW.name());
            }else{
                System.out.println("INVALID CITY");
                System.exit(0);
            }
            
        }else{
            System.out.println("INVALID LANGUAGE");
            System.exit(0);
        }

        mergePaper.append("_").append(pageStr).append(".pdf");
        
        urlStr.append(dateStr);
        urlStr.append("/PagePrint/");
        urlStr.append(pageStr);
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

        System.out.println("********************************************************");
        System.out.println("***********    CREATED BY -- Punit Agrawal   ***********");
        System.out.println("*******    Contact me @ punit.agrawal@gmx.com  *********");
        System.out.println("********************************************************");
        System.out.println("");
        //String[] arg = {"MAIN","ENG","MUM"};
        if(args.length<2){
            System.out.println("USAGE: java -jar HTPDF.jar <first_three_letters_of_language> <first_three_letters_of_city> <Directory_to_store_pdf>");
            System.out.print("Supported Languages: ");
            for(Language l:Language.values()){
                System.out.print(l.name()+"  ");
            }
            System.out.println();
            System.out.println("Supported Cities: ");
            System.out.print("    "+Language.ENGLISH.name()+": ");
            for(English_City c:English_City.values()){
                System.out.print(c.name()+"  ");
            }
            System.out.println();

            System.out.print("    "+Language.HINDI.name()+": ");
            for(Hindi_City c:Hindi_City.values()){
                System.out.print(c.name()+"  ");
            }
            System.out.println();
            System.exit(0);
        }
        
        if(args.length>=3){
            basefile = args[2];
            if(!args[2].endsWith("\\")&& !args[2].endsWith("/"))
                    basefile+="/";

            
        }
        buildURL(args);
        System.out.println("GETTING PDFs !!!! ");
        ExecutorService es = Executors.newFixedThreadPool(pagecount);

        for (int i = 0; i < pagecount; i++) {
            final String localStr = urlStr.toString() + getThreeDigitString(i + 1) + ".pdf";
            Callable<ByteArrayInputStream> c = new Worker(localStr, i);
            futures.add(es.submit(c));
        }

        for (Future<ByteArrayInputStream> f : futures) {
            try {
                InputStream i = f.get();
                if(i != null)
                    pdfs.add(i);
            } catch (InterruptedException ex) {
                //Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            } catch (ExecutionException ex) {
                //Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        es.shutdown();


        OutputStream output = null;
        try {
            output = new FileOutputStream(mergePaper.toString());
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }

        //Combine the pdfs
        System.out.println("MERGING PDFs");
        mergeStreams(pdfs, mergePaper.toString());

    }

    public static String getThreeDigitString(int no) {
        if (no >= 0 && no <= 9) {
            return "00" + no;

        } else if (no <= 99) {
            return "0" + no;
        } else {
            return "Error";
        }

    }

    public static void mergeFiles(List<String> filesToBeMerged,
            String mergedFileLocation) {
        PDFMergerUtility pdfmu = new PDFMergerUtility();
        for (String s : filesToBeMerged) {
            pdfmu.addSource(s);
        }
        pdfmu.setDestinationFileName(mergedFileLocation);
        try {
            pdfmu.mergeDocuments();
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        } catch (COSVisitorException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static void mergeStreams(List<InputStream> streamsToBeMerged,
            String mergedFileLocation) {
        PDFMergerUtility pdfmu = new PDFMergerUtility();
        for (InputStream s : streamsToBeMerged) {
            pdfmu.addSource(s);
        }
        pdfmu.setDestinationFileName(mergedFileLocation);
        try {
            pdfmu.mergeDocuments();
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        } catch (COSVisitorException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static void deleteMyFiles(List<String> filesToBeDeleted) {
        for (String str : filesToBeDeleted) {
            File f = new File(str);
            if (f.exists() && f.canWrite() && !f.isDirectory()) {
                f.delete();
            } else {
                System.out.println("" + f.exists() + " " + f.canWrite() + " " + f.isDirectory());
            }
        }
    }
}

class Worker implements Callable {

    private final String localStr;
    private final int id;

    public Worker(String localstr, int id) {
        this.localStr = localstr;
        this.id = id;
    }

    public ByteArrayInputStream call() {
        try {
            URL url = null;
            url = new URL(localStr);
            //System.out.println("Getting PDF from URL: " + localStr);
            URLConnection uc = url.openConnection();
            int contentLength = uc.getContentLength();
            InputStream raw = uc.getInputStream();
            InputStream in = new BufferedInputStream(raw);
            Main.buf[id] = new byte[contentLength];
            int bytesRead = 0;
            int offset = 0;
            while (offset < contentLength) {
                bytesRead = in.read(Main.buf[id], offset, Main.buf[id].length - offset);
                if (bytesRead == -1) {
                    break;
                }
                offset += bytesRead;
            }
            in.close();
            if (offset != contentLength) {
                try {
                    throw new IOException("Only read " + offset + " bytes; Expected " + contentLength + " bytes");
                } catch (IOException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
            }


        } catch (IOException ex) {
           // Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            return new ByteArrayInputStream(Main.buf[id]);
        }
    }
}
